package cn.com.yusys.yusp.admin.service;

import cn.com.yusys.yusp.uaa.client.dto.CodeAndMessage;
import cn.com.yusys.yusp.uaa.client.dto.PasswordStrategyDto;
import cn.com.yusys.yusp.uaa.domain.UaaCrelStra;
import cn.com.yusys.yusp.uaa.repository.mapper.CredentialStrategyMapper;
import cn.com.yusys.yusp.uaa.repository.mapper.UaaPasswordLogMapper;
import cn.com.yusys.yusp.uaa.service.impl.PasswordStrategyServiceImpl;
import cn.com.yusys.yusp.uaa.service.util.BCRSAUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class PasswordService {
    private Logger logger = LoggerFactory.getLogger(PasswordStrategyServiceImpl.class);
    private static final String FAILED = "1000";
    private static final String NO_STRATEGY = "1002";
    private static final String UNSUCCESSFULLY_CHECKED = "1003";
    private static final String SUCCESSFULLY_CHECKED = "1001";
    private static final String UNSUCCESSFULLY_DECRYPTED = "1004";
    @Autowired
    private CredentialStrategyMapper mapper;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private UaaPasswordLogMapper uaaPasswordLogMapper;


    public static String getNoStrategy() {
        return "1002";
    }

    public static String getUnsuccessfullyChecked() {
        return "1003";
    }

    public static String getSuccessfullyChecked() {
        return "1001";
    }

    public static String getUnsuccessfullyDecrypted() {
        return "1004";
    }

    public CredentialStrategyMapper getMapper() {
        return this.mapper;
    }

    public void setMapper(CredentialStrategyMapper mapper) {
        this.mapper = mapper;
    }

    public PasswordEncoder getPasswordEncoder() {
        return this.passwordEncoder;
    }

    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }

    public UaaPasswordLogMapper getUaaPasswordLogMapper() {
        return this.uaaPasswordLogMapper;
    }

    public void setUaaPasswordLogMapper(UaaPasswordLogMapper uaaPasswordLogMapper) {
        this.uaaPasswordLogMapper = uaaPasswordLogMapper;
    }

    public CodeAndMessage checkPwd(String sysId, String passward, String userId) {
        CodeAndMessage result = new CodeAndMessage();
        StringBuilder message = new StringBuilder();
        StringBuilder code = new StringBuilder();
        List<Object> i18nData = new ArrayList();
        boolean flag = true;
        this.logger.info("Start password verification");
        this.logger.info("To query password policy information:");
        List<UaaCrelStra> list = this.mapper.selectBySysId(sysId);
        if (list.size() > 0) {
            int length = list.size();

            for(int i = 0; i < length; ++i) {
                UaaCrelStra info = (UaaCrelStra)list.get(i);
                String cerlName = info.getCerlName();
                String crelDetail = info.getCrelDetail();
                PasswordStrategyDto res = new PasswordStrategyDto();
                if ("PASSWD_COMPLEX_RULE".equals(cerlName)) {
                    res = this.pwdComplex(passward, crelDetail);
                } else if ("PASSWD_LENGTH_RULE".equals(cerlName)) {
                    res = this.pwdLength(passward, crelDetail);
                } else if ("PASSWD_REPETCHG_RULE".equals(cerlName)) {
                    res = this.pwdHistory(passward, crelDetail, userId);
                } else if ("PASSWD_REPETNUMBER_RULE".equals(cerlName)) {
                    res = this.pwdNoRepeatLength(passward, crelDetail);
                } else if ("PASSWD_SEQUNNUMBER_RULE".equals(cerlName)) {
                    res = this.pwdSeries(passward, crelDetail);
                }

                if (res != null && !res.isFlag()) {
                    if (message.length() == 0) {
                        message.append(res.getMessage());
                    } else {
                        message.append("|").append(res.getMessage());
                    }

                    if (code.length() == 0) {
                        code.append(res.getCode());
                    } else {
                        code.append("|").append(res.getCode());
                    }

                    if (res.getI18nData() != null && !res.getI18nData().isEmpty()) {
                        i18nData.add(res.getI18nData());
                    }

                    flag = false;
                }

                if (flag) {
                    result.setCode(String.valueOf(10100001));
                    result.setMessage("校验通过");
                } else {
                    result.setCode(code.toString());
                    result.setMessage(message.toString());
                    result.setI18nData(i18nData);
                }
            }
        } else {
            result.setCode(String.valueOf(10100002));
            result.setMessage("没有相应的密码策略，暂不需要校验密码");
        }

        this.logger.info("Password verification finished");
        return result;
    }

    public PasswordStrategyDto pwdComplex(String pwd, String detail) {
        PasswordStrategyDto result = new PasswordStrategyDto();
        boolean flag = false;
        Map<String, String> reg = new HashMap();
        reg.put("number", "^[0-9]*$");
        reg.put("upperchar", "^[A-Z]+$");
        reg.put("lowerchar", "^[a-z]+$");
        reg.put("ifspecchar", ".*[`~!@#$%^&*()+=|{}':;',\\\\[\\\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？\\\\\\\\]+.*");
        reg.put("ifnumber", ".*\\d+.*");
        reg.put("iflowerchar", ".*[a-z]+.*");
        reg.put("ifupperchar", ".*[A-Z]+.*");
        if (!"number".equals(detail) && !"upperchar".equals(detail) && !"lowerchar".equals(detail)) {
            if ("number,upperchar".equals(detail)) {
                if (pwd.matches((String)reg.get("ifnumber")) && !pwd.matches((String)reg.get("iflowerchar")) && pwd.matches((String)reg.get("ifupperchar")) && !pwd.matches((String)reg.get("ifspecchar"))) {
                    flag = true;
                } else {
                    result.setMessage("只能且必须包含数字和大写字母");
                    result.setCode(String.valueOf(10100009));
                }
            } else if ("number,lowerchar".equals(detail)) {
                if (pwd.matches((String)reg.get("ifnumber")) && pwd.matches((String)reg.get("iflowerchar")) && !pwd.matches((String)reg.get("ifupperchar")) && !pwd.matches((String)reg.get("ifspecchar"))) {
                    flag = true;
                } else {
                    result.setCode(String.valueOf(10100010));
                    result.setMessage("只能且必须包含数字和小写字母");
                }
            } else if ("lowerchar,upperchar".equals(detail)) {
                if (!pwd.matches((String)reg.get("ifnumber")) && pwd.matches((String)reg.get("iflowerchar")) && pwd.matches((String)reg.get("ifupperchar")) && !pwd.matches((String)reg.get("ifspecchar"))) {
                    flag = true;
                } else {
                    result.setMessage("只能且必须包含大写和小写字母");
                    result.setCode(String.valueOf(10100011));
                }
            } else if ("lowerchar,number,upperchar".equals(detail)) {
                if (pwd.matches((String)reg.get("ifnumber")) && pwd.matches((String)reg.get("iflowerchar")) && pwd.matches((String)reg.get("ifupperchar")) && !pwd.matches((String)reg.get("ifspecchar"))) {
                    flag = true;
                } else {
                    result.setMessage("只能且必须包含数字、大写、小写字母");
                    result.setCode(String.valueOf(10100012));
                }
            } else if ("specchar".equals(detail)) {
                if (!pwd.matches((String)reg.get("ifnumber")) && !pwd.matches((String)reg.get("iflowerchar")) && !pwd.matches((String)reg.get("ifupperchar")) && pwd.matches((String)reg.get("ifspecchar"))) {
                    flag = true;
                } else {
                    result.setMessage("只能设置特殊字符");
                    result.setCode(String.valueOf(10100013));
                }
            } else if ("number,specchar".equals(detail)) {
                if (pwd.matches((String)reg.get("ifnumber")) && !pwd.matches((String)reg.get("iflowerchar")) && !pwd.matches((String)reg.get("ifupperchar")) && pwd.matches((String)reg.get("ifspecchar"))) {
                    flag = true;
                } else {
                    result.setMessage("只能且必须包含数字和特殊字符");
                    result.setCode(String.valueOf(10100014));
                }
            } else if ("upperchar,specchar".equals(detail)) {
                if (!pwd.matches((String)reg.get("ifnumber")) && !pwd.matches((String)reg.get("iflowerchar")) && pwd.matches((String)reg.get("ifupperchar")) && pwd.matches((String)reg.get("ifspecchar"))) {
                    flag = true;
                } else {
                    result.setMessage("只能且必须包含大写和特殊字符");
                    result.setCode(String.valueOf(10100015));
                }
            } else if ("lowerchar,specchar".equals(detail)) {
                if (!pwd.matches((String)reg.get("ifnumber")) && pwd.matches((String)reg.get("iflowerchar")) && !pwd.matches((String)reg.get("ifupperchar")) && pwd.matches((String)reg.get("ifspecchar"))) {
                    flag = true;
                } else {
                    result.setMessage("只能且必须包含小写和特殊字符");
                    result.setCode(String.valueOf(10100016));
                }
            } else if ("lowerchar,number,specchar".equals(detail)) {
                if (pwd.matches((String)reg.get("ifnumber")) && pwd.matches((String)reg.get("iflowerchar")) && !pwd.matches((String)reg.get("ifupperchar")) && pwd.matches((String)reg.get("ifspecchar"))) {
                    flag = true;
                } else {
                    result.setMessage("只能且必须包含小写、数字和特殊字符");
                    result.setCode(String.valueOf(10100017));
                }
            } else if ("lowerchar,specchar,upperchar".equals(detail)) {
                if (!pwd.matches((String)reg.get("ifnumber")) && pwd.matches((String)reg.get("iflowerchar")) && pwd.matches((String)reg.get("ifupperchar")) && pwd.matches((String)reg.get("ifspecchar"))) {
                    flag = true;
                } else {
                    result.setMessage("只能且必须包含小写、大写和特殊字符");
                    result.setCode(String.valueOf(10100018));
                }
            } else if ("number,specchar,upperchar".equals(detail)) {
                if (pwd.matches((String)reg.get("ifnumber")) && !pwd.matches((String)reg.get("iflowerchar")) && pwd.matches((String)reg.get("ifupperchar")) && pwd.matches((String)reg.get("ifspecchar"))) {
                    flag = true;
                } else {
                    result.setMessage("只能且必须包含大写、数字和特殊字符");
                    result.setCode(String.valueOf(10100019));
                }
            } else if ("lowerchar,number,specchar,upperchar".equals(detail)) {
                if (pwd.matches((String)reg.get("ifnumber")) && pwd.matches((String)reg.get("iflowerchar")) && pwd.matches((String)reg.get("ifupperchar")) && pwd.matches((String)reg.get("ifspecchar"))) {
                    flag = true;
                } else {
                    result.setMessage("只能且必须包含数字、大写、小写和特殊字符");
                    result.setCode(String.valueOf(10100020));
                }
            } else {
                result.setCode(String.valueOf(10100020));
                result.setMessage("密码复杂策略不支持的配置类型");
            }
        } else {
            flag = pwd.matches((String)reg.get(detail));
            if (!flag && "number".equals(detail)) {
                result.setMessage("只能设置数字");
                result.setCode(String.valueOf(10100006));
            } else if (!flag && "upperchar".equals(detail)) {
                result.setCode(String.valueOf(10100007));
                result.setMessage("只能设置大写字母");
            } else if (!flag && "lowerchar".equals(detail)) {
                result.setCode(String.valueOf(10100008));
                result.setMessage("只能设置小写字母");
            }
        }

        result.setFlag(flag);
        return result;
    }

    public PasswordStrategyDto pwdLength(String pwd, String detail) {
        PasswordStrategyDto result = new PasswordStrategyDto();
        int length = pwd.length();
        int limit = Integer.parseInt(detail);
        if (length >= limit) {
            result.setMessage("");
            result.setFlag(true);
        } else {
            result.setMessage("密码不能少于" + detail + "位");
            result.setCode(String.valueOf(10100021));
            result.setI18nData(detail);
            result.setFlag(false);
        }

        return result;
    }

    public PasswordStrategyDto pwdHistory(String pwd, String detail, String userId) {
        PasswordStrategyDto result = new PasswordStrategyDto();
        boolean flag = true;
        int limit = Integer.parseInt(detail);
        if (limit > 0) {
            List<String> list = this.uaaPasswordLogMapper.getAdminSmPasswordLog(userId);
            limit = limit > list.size() ? list.size() : limit;
            if (list.size() > 0) {
                for(int i = 0; i < limit; ++i) {
                    String oldPwd = (String)list.get(i);
                    if (this.passwordEncoder.matches(pwd, oldPwd)) {
                        flag = false;
                        break;
                    }
                }
            } else {
                flag = true;
            }
        } else {
            flag = true;
        }

        if (!flag) {
            result.setMessage("密码不能与最近" + detail + "次的密码重复");
            result.setCode(String.valueOf(10100022));
            result.setI18nData(detail);
            result.setFlag(false);
        } else {
            result.setMessage("");
            result.setFlag(true);
        }

        return result;
    }

    public PasswordStrategyDto pwdNoRepeatLength(String pwd, String detail) {
        PasswordStrategyDto result = new PasswordStrategyDto();
        int limit = Integer.parseInt(detail);
        int c = 0;
        int a1 = 0;
        int count = pwd.length() - limit;
        if (count >= 0) {
            for(int j = 0; j < count; ++j) {
                for(int i = j + 1; i < j + limit; ++i) {
                    if (pwd.charAt(j) == pwd.charAt(i)) {
                        ++c;
                    }
                }

                if (c == limit - 1) {
                    ++a1;
                }

                c = 0;
            }
        }

        if (a1 > 0) {
            result.setMessage("密码连续重复的字符数超过最大长度:" + detail);
            result.setCode(String.valueOf(10100023));
            result.setI18nData(detail);
            result.setFlag(false);
        } else {
            result.setFlag(true);
        }

        return result;
    }

    public PasswordStrategyDto pwdSeries(String pwd, String detail) {
        PasswordStrategyDto result = new PasswordStrategyDto();
        int limit = Integer.parseInt(detail);
        int a = 0;
        int b = 0;
        int a1 = 0;
        int count = pwd.length() - limit;
        if (count >= 0) {
            for(int j = 0; j < count; ++j) {
                for(int i = j; i < j + limit; ++i) {
                    int tmp = pwd.charAt(i) - pwd.charAt(i + 1);
                    if (tmp == 1) {
                        ++a;
                    } else if (tmp == -1) {
                        ++b;
                    }
                }

                if (a == limit - 1 || b == limit - 1) {
                    ++a1;
                }

                a = 0;
                b = 0;
            }
        }

        if (a1 > 0) {
            result.setMessage("密码连续字符的字符数超过最大长度:" + detail);
            result.setCode(String.valueOf(10100024));
            result.setI18nData(detail);
            result.setFlag(false);
        } else {
            result.setFlag(true);
            result.setMessage("");
        }

        return result;
    }

    public String decrypt(String cipherText) {
        try {
            cipherText = BCRSAUtil.decrypt(cipherText);
            return cipherText;
        } catch (Exception var3) {
            this.logger.error("BC decryption failed", var3);
            return "";
        }
    }

    public CodeAndMessage matchPassword(String rawPassword, String encodedPassword) {
        CodeAndMessage result = new CodeAndMessage();
        if (this.passwordEncoder.matches(rawPassword, encodedPassword)) {
            result.setCode(String.valueOf(10100001));
            result.setMessage("字符匹配");
        } else {
            result.setCode(String.valueOf(10100000));
            result.setMessage("字符不匹配");
        }

        return result;
    }

    public CodeAndMessage matchUsingPwd(String pwd, String pwdType, String userId) {
        String rawPwd = "";
        new CodeAndMessage();
        if ("2".equals(pwdType)) {
            rawPwd = this.decrypt(pwd);
        } else {
            rawPwd = pwd;
        }

        String usingPwd = "";
        List<String> list = this.uaaPasswordLogMapper.getAdminSmPasswordLog(userId);
        if (list != null && list.size() > 0) {
            usingPwd = (String)list.get(0);
        }

        CodeAndMessage result = this.matchPassword(rawPwd, usingPwd);
        if (String.valueOf(10100000).equals(result.getCode())) {
            result.setMessage("不匹配登录用户当前密码，请检查原密码");
        } else {
            result.setMessage("登录密码校验通过");
        }

        return result;
    }
}
